這篇文章是閱讀Asabeneh的30 Days Of Python: Day 26 - Python for Web後的學習筆記與心得。
原文章中 Day 24 與 Day 25 分別是說明 NumPy 以及 pandas 這兩個函式庫的函式,因為應用的部分著墨不多,就像是在讀官方 API 文件的感覺,因此我選擇略過不寫,直接跳到原文的 Day 26,這章會使用 Flask 做一個簡易的後端。
首先,需要架設一個環境,原文中給的資料夾結構如下,裡面是後續建置會用到的檔案:
├── Procfile
├── app.py
├── env
│ ├── bin
├── requirements.txt
├── static
│ └── css
│ └── main.css
└── templates
├── about.html
├── home.html
├── layout.html
├── post.html
└── result.html
然後需要啟動 Day 26 提到的虛擬環境,若尚未安裝可以在 CLI 輸入pip install virtualenv
執行安裝:
(這是 Windows 的創建及啟動語法)
python -m venv venv
venv\Scripts\activate
pip install Flask
pip freeze > requirements.txt
"venv/*" > .gitignore
virtualenv
產生了一個 venv
資料夾Flask
套件pip freeze
的輸出寫進 requirements.txt
.gitignore
檔案並排除 venv/
資料夾底下的檔案先在資料夾 (原文中放在 python_for_web
) 中,創建一個 app.py
的檔案,內容為:
#
from flask import Flask
import os
app = Flask(__name__)
@app.route('/') # Home
def home ():
return <h1>Home</h1>
@app.route('/about')
def about():
return <h1>About</h1>
if __name__ == '__main__':
port = int(os.environ.get('PORT', 5000))
app.run(debug=True, host='0.0.0.0', port = port)
__name__
是 Python 在創造模組 (module) 時會自動加入的屬性,當模組是主要被執行的對象時__name__ = '__main__'
否則會等於被引入的模組名稱。
如果沒有寫 if 判斷式的話,若這個模組被其他模組引入,就會在編譯的過程中被執行,通常這不會是我們想要的。
執行 python app.py
後可以看到:
* Running on http://127.0.0.1:5000
此時便能透過瀏覽器去拜訪 http://127.0.0.1:5000
,看到 <h1>Home</h1>
這個元素。
當我們拜訪網站時,應該不單純是只要 <h1>...</h1>
這樣的字串;Flask 能夠回傳 html
檔案:
templates
home.html
和 about.html
home.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Home</title>
</head>
<body>
<h1>Welcome Home</h1>
</body>
</html>
about.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>About</title>
</head>
<body>
<h1>About Us</h1>
</body>
</html>
flask
新引入render_template
函式,並在路由底下回傳 render_template(<filename>)
:from flask import Flask, render_template
# 沒改動的地方省略
@app.route('/') # Home
def home ():
return render_template('home.html')
@app.route('/about')
def about():
return render_template('about.html')
這麼一來 Flask 就會去 templates 資料夾抓到 home.html
和 about.html
並在使用者拜訪對應的位址時回傳對應的HTML檔案。?
Flask 借助這個模板引擎,讓我們建立 HTML 模板並結合其他 HTML 檔案使用,也可以將 app.py
中的資料嵌入到我們的 HTML 檔案。
從上面的例子可以看到,home.html
和 about.html
只有 h1
標籤內的內容不同:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>About</title>
</head>
<body>
<!-- 只有這裡不一樣 -->
</body>
</html>
透過 Jinja2 的語法,我們能避免重複撰寫這些共通的內容;在 templates 資料夾中新增一個 layout.html
檔案,內容為:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Title</title>
</head>
<body>
{% block contents %}{% endblock %}
</body>
</html>
然後在原本的 home.html
就能改成:
{% extends "layout.html" %}
{% block contents %}
<h1>Welcome Home</h1>
{% endblock %}
about.html
也是:
{% extends "layout.html" %}
{% block contents %}
<h1>About Us</h1>
{% endblock %}
經過上面的改寫,可以注意到瀏覽器的頁籤 (tab) 還是顯示 "Title",這是因為 layout.html
裡 <title>Title</title>
這個標籤內的內容並沒有透過 Jinja 來依資料改變。
在 app.py
中,我們使用的 render_template(<template>)
可以接受第二個參數:
# @filename = app.py
@app.route('/') # Home
def home ():
return render_template('home.html', title = 'Home')
@app.route('/about')
def about():
return render_template('about.html', title = 'About Us')
然後在 layout.html
裡把 title
標籤的內容修改為:
<title>{{ title }}</title>
這個
{{ data }}
的語法叫做 Mustache syntax
這樣就能看到 tab 的名稱隨著我們去到不同的路由改變了。